package com.iflytek.jcy.supervise.job.common.util;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

/**
 * @author <a href=mailto:ktyi@iflytek.com>伊开堂</a>
 * @date 2022/5/25
 */
public abstract class ThreadPoolUtils {
    protected static final Logger logger = LoggerFactory.getLogger(ThreadPoolUtils.class);

    /** CPU核心数 */
    public static final int CPU_SIZE = Runtime.getRuntime().availableProcessors();

    /**
     * 创建线程池
     *
     * @param threadSize       线程数量(core线程数和max线程数都等于该值)
     * @param threadNamePrefix 线程名前缀, 例: img-format
     * @param queueCapacity    队列长度
     */
    public static ThreadPoolExecutor createExecutor(int threadSize, String threadNamePrefix, int queueCapacity) {
        return createExecutor(threadSize, threadNamePrefix, queueCapacity, new ThreadPoolExecutor.CallerRunsPolicy());
    }

    /**
     * 创建线程池
     *
     * @param threadSize       线程数量(core线程数和max线程数都等于该值)
     * @param threadNamePrefix 线程名前缀, 例: img-format
     * @param queueCapacity    队列长度
     * @param policy           拒绝策略
     *
     * @return
     */
    public static ThreadPoolExecutor createExecutor(int threadSize, String threadNamePrefix, int queueCapacity,
            ThreadPoolExecutor.CallerRunsPolicy policy) {
        Assert.isTrue(threadSize > 0, "线程数threadSize必须大于0");
        Assert.isTrue(queueCapacity > 0, "队列容量queueCapacity必须大于0");

        ThreadFactory threadFactory = new ThreadFactoryBuilder().setDaemon(false).setNameFormat(threadNamePrefix +
                                                                                                        "-%d").setUncaughtExceptionHandler((t, e) -> logger.error("线程 " + t + " 异常结束", e))
                                                                .build();
        return new ThreadPoolExecutor(threadSize, threadSize, 0, TimeUnit.SECONDS,
                                      new LinkedBlockingQueue<>(queueCapacity), threadFactory, policy);
    }

    /**
     * 获取线程池监控信息
     *
     * @param executor
     *
     * @return 格式: 执行中线程数: 5(50%, 2-6-8-10), 队列内任务数: 300(30%, 1000: 300|700)
     */
    public static String poolInfo(ThreadPoolExecutor executor) {
        if (executor == null) {
            return null;
        }

        // 核心线程数
        int corePoolSize = executor.getCorePoolSize();
        // 历史线程数峰值
        int largestPoolSize = executor.getLargestPoolSize();
        // 最大线程数
        int maximumPoolSize = executor.getMaximumPoolSize();
        // 当前活跃线程数(正在执行任务)
        int activeCount = executor.getActiveCount();
        // 当前线程数(可能部分在休眠)
        int poolSize = executor.getPoolSize();

        BlockingQueue<Runnable> queue = executor.getQueue();
        // 队列内任务数
        int queueSize = queue.size();
        // 队列剩余容量
        int remainingCapacity = queue.remainingCapacity();
        // 队列总容量
        int queueCapacity = queueSize + remainingCapacity;

        int threadPercent = (int) (activeCount / (float) maximumPoolSize * 100);
        int queuePercent = (int) (queueSize / (float) queueCapacity * 100);

        // 执行中线程数: 5(50%, 2-8-8-10), 队列内任务数: 300(30%, 1000: 300|700)
        StringBuilder sb = new StringBuilder("执行中线程数: ");
        sb.append(activeCount).append("(").append(threadPercent).append("%, ");
        sb.append(corePoolSize).append("-").append(poolSize).append("-").append(largestPoolSize).append("-").append(
                maximumPoolSize).append("), ");
        sb.append("队列内任务数: ").append(queueSize).append("(").append(queuePercent).append("%, ").append(queueCapacity)
          .append(": ").append(queueSize).append("|").append(remainingCapacity).append(")");
        return sb.toString();
    }

}
